package com.ttctracker.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.ttctracker.R;
import com.ttctracker.classes.Route;
import com.ttctracker.classes.StopItem;
import com.ttctracker.util.SqlAdapter;

public class UserLocationHandler implements LocationListener, OnCancelListener {
	/** Class used to "listen" to updates in GPS location */

	private ProgressDialog dialog;
	private Context context;
	private RouteMapItemizedOverlay itemizedOverlay;
	private MapView mapView;
	private List<Overlay> mapOverlays;
	private MapController mController;
	private static Drawable locationMarker;
	private boolean gotUserLocation;
	private boolean isInitialUpdate = true;
	private Location lastUpdatedLocation;

	public UserLocationHandler(RouteMapItemizedOverlay itemizedOverlay,
			MapView mapView) {
		this.itemizedOverlay = itemizedOverlay;
		this.mapView = mapView;
		mapOverlays = mapView.getOverlays();
		mController = mapView.getController();
	}

	public void start(Context context) {
		/** Called when the listener is started */

		this.context = context;

		locationMarker = context.getResources().getDrawable(R.drawable.ic_gps);
		locationMarker.setBounds(0, 0, locationMarker.getIntrinsicWidth(),
				locationMarker.getIntrinsicHeight());

		// Show progress dialog to the user
		dialog = new ProgressDialog(context);
		dialog.setMessage("Getting GPS Location. Please Wait.");
		dialog.setOnCancelListener(this);
		dialog.show();
	}

	@Override
	public void onLocationChanged(Location location) {
		/** Called when the GPS location changes */
		GeoPoint userLocation = new GeoPoint(
				(int) (location.getLatitude() * 1e6),
				(int) (location.getLongitude() * 1e6));
		// close progress dialog (should only happen on first update)
		if (dialog.isShowing()) {

			if (isInitialUpdate) {
				float[] diffDistance = new float[1];
				if (lastUpdatedLocation == null) {
					diffDistance[0] = 99999;
				} else {
					Location.distanceBetween(location.getLatitude(),
							location.getLongitude(),
							lastUpdatedLocation.getLatitude(),
							lastUpdatedLocation.getLongitude(), diffDistance);

				}
				isInitialUpdate = false;
				if (diffDistance[0] >= 1000) {
					new GetNearByRoutesTask(context).execute(location);
				}else {
					dialog.dismiss();
					updateUserLocationOverlay(userLocation);
				}

			}

		} else {
			
			updateUserLocationOverlay(userLocation);
			//mController.animateTo(userLocation);
		}
		
	}
	
	private void updateUserLocationOverlay(GeoPoint userLocation){
		//if (dialog.isShowing()) {
			
			
			// create overlay
			OverlayItem overlay = new OverlayItem(userLocation, "", "");
			overlay.setMarker(locationMarker);

			// replace previous overlay with the new one
			itemizedOverlay.updateNavOverlay(overlay);

			if (mapOverlays.isEmpty()) {
				// no markers on the map
				mapOverlays.add(itemizedOverlay);
			}
			
			// invalidate current map in order to force a redraw of the markers
			mapView.invalidate();
		//}
		
	}

	public void turningOffGPS(Location lastUpdatedLocation) {
		isInitialUpdate = true;
		this.lastUpdatedLocation = lastUpdatedLocation;
	}

	@Override
	public void onProviderDisabled(String provider) {
		/** Called when the GPS provider gets disabled */

		// if progress is showing, cancel it
		if (dialog.isShowing()) {
			dialog.dismiss();
		}

		// show alert dialog to inform the user
		try {
			AlertDialog.Builder builder = new AlertDialog.Builder(this.context);

			builder.setMessage("GPS location is unavailable.");
			builder.setCancelable(false);
			builder.setPositiveButton("OK",
					new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int id) {
						}
					});
			AlertDialog alert = builder.create();
			alert.show();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/** Abstract methods which need to be overridden */
	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public void onCancel(DialogInterface dialog) {
		((Map)context).onGPSDialogCancel();
	}

	private class GetNearByRoutesTask extends
			AsyncTask<Location, Void, ArrayList<Route>> {
		private Context context;
		private GeoPoint userLocation;

		public GetNearByRoutesTask(Context context) {
			this.context = context;
		}

		@Override
		protected ArrayList<Route> doInBackground(Location... params) {
			double userLat = params[0].getLatitude();
			double userLon = params[0].getLongitude();
			// get coordinates
			int lat = (int) (userLat * 1E6);
			int lng = (int) (userLon * 1E6);
			GeoPoint point = new GeoPoint(lat, lng);
			userLocation = point;
			SqlAdapter adapter = new SqlAdapter(context);
			adapter.openDB();
			// String resultsString="";
			if (adapter.isOpen()) {
				ArrayList<Route> nearByRoutes = adapter.getNearByRoutes(
						userLat, userLon);

				adapter.close();
				return nearByRoutes;
			}

			return null;
		}

		@Override
		protected void onPostExecute(ArrayList<Route> result) {
			dialog.dismiss();
			updateUserLocationOverlay(userLocation);
			mController.animateTo(userLocation);
			if (result != null) {
				itemizedOverlay.clear();
				GeoPoint geoPoint = null;
				for (Route route : result) {
					int size = route.get_stopItems().size();
					StopItem[] stops = route.get_stopItems().values()
							.toArray(new StopItem[size]);
					for (StopItem stopItem : stops) {
						geoPoint = new GeoPoint(
								(int) (stopItem.get_lat() * 1e6),
								(int) (stopItem.get_lon() * 1e6));
						itemizedOverlay.addOverlay(new RouteMapStopOverlayItem(
								geoPoint, stopItem.get_title(),
								"Tap to see predictions.", stopItem));
					}
				}
				itemizedOverlay.restoreNavOverlay();
				itemizedOverlay.populate_overlayItem();

				mController.setZoom(17);
				// UserLocationHandler.this.start(context)
				// mapView.invalidate();
			}
			// Toast.makeText(context, nearByString, Toast.LENGTH_LONG).show();
		}
	}

}
